/*
 * ProductClient.java
 *
 * $Id: ProductClient.java,v 1.22 2009-10-27 10:09:31 mario Exp $
 */
package org.ceteca.explica.client.warehouse;

import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.ceteca.explica.client.ClientContext;
import org.ceteca.explica.client.gui.ExplicaDetailEntityView;
import org.ceteca.explica.client.gui.ExplicaEditEntityView;
import org.ceteca.explica.client.gui.ExplicaEntitySelectionView;
import org.ceteca.explica.client.gui.ExplicaEntityView;
import org.ceteca.explica.client.gui.ExplicaExtensionFieldsView;
import org.ceteca.explica.client.gui.ExplicaGUIBuilder;
import org.ceteca.explica.client.gui.ImageUtils;
import org.ceteca.explica.client.gui.common.CommonClient;
import org.ceteca.explica.client.traceability.gui.TraceabilityTreeView;
import org.ceteca.explica.core.ExplicaException;
import org.ceteca.explica.core.InterfaceErrors;
import org.ceteca.explica.core.InterfaceExplica;
import org.ceteca.explica.core.common.BarcodeTypeOT;
import org.ceteca.explica.core.common.BaseVO;
import org.ceteca.explica.core.common.CommonManager;
import org.ceteca.explica.core.common.ImageOT;
import org.ceteca.explica.core.common.MultiSelectionSubentityOT;
import org.ceteca.explica.core.common.PriceListLineOT;
import org.ceteca.explica.core.common.RegistryOT;
import org.ceteca.explica.core.common.SelectionSubentityOT;
import org.ceteca.explica.core.common.VatTypeOT;
import org.ceteca.explica.core.installer.EntityOT;
import org.ceteca.explica.core.installer.SubentityOT;
import org.ceteca.explica.core.partners.InterfacePartners;
import org.ceteca.explica.core.partners.RappelIntervalOT;
import org.ceteca.explica.core.util.BarcodeGenerator;
import org.ceteca.explica.core.util.OperationResult;
import org.ceteca.explica.core.util.ResultMessage;
import org.ceteca.explica.core.warehouse.InterfaceWarehouse;
import org.ceteca.explica.core.warehouse.InterfaceWarehouseErrors;
import org.ceteca.explica.core.warehouse.MeasureUnitOT;
import org.ceteca.explica.core.warehouse.ProductGroupOT;
import org.ceteca.explica.core.warehouse.ProductOT;
import org.ceteca.explica.core.warehouse.WarehouseManager;
import org.ceteca.javaglade.Gui;
import org.ceteca.javaglade.InterfaceGladeGtk;
import org.ceteca.javaglade.toolkit.swt.SwtDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;

public class ProductClient extends CommonClient {
	/** Product images array list to iterate over the selected product images catalog */
	private ArrayList<ImageOT> selProductImages;
	/** Index of the currently shown product image */
	private int currentImageIndex;
	/** Instance of the product listener to handle product edition events */
	private ProductClientListener productListener;
	
	/**
     * Message for logging the entity glade configuration file path.
     */
    public static final String EXPLICA_LOG_EDITPRODUCT_GLADEPATH = "The product edition interface configuration file has been found at this path: %s";
    
	/**
	 * Default constructor for ProductClient objects.
	 */
	public ProductClient() {
		super(	ProductOT.class,
				InterfaceWarehouse.EXPLICA_EDIT_PRODUCT_GLADE_PATH,
				InterfaceWarehouse.EDIT_PRODUCT_DIALOG_NAME);
    	ClientContext.getInstance().getLogger().debug("Constructor de ProductClient");
    	this.selProductImages = null;
    	this.currentImageIndex = 0;
    	this.entSelView = null;

		// Build the listener for the product edition events
		this.productListener = new ProductClientListener(this.logger, this);
	}
	
	@Override
	public ArrayList getEntityFields() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ArrayList queryEntity(String fieldId, String value) {
		this.lRegistries = null;
		
		try {
			WarehouseManager manager = this.getRemoteWarehouse();
			System.out.println("WarehouseManager located");
			
			this.lRegistries = (ArrayList)manager.queryProducts(fieldId, value);
			StringBuffer logInfo = new StringBuffer();
			logInfo.append("Queried products: \n");
			for (int i=0; this.lRegistries != null && i<this.lRegistries.size(); i++) {
				System.out.println(this.lRegistries.get(i));
				logInfo.append(String.format("\n\t%d --> %s", i, this.lRegistries.get(i)));
			}
			this.logger.debug(logInfo.toString());
		}
		catch (AccessException aEx) {
			System.err.println("Se rechazó el acceso. Su sistema no tiene los permisos necesarios para realizar la operación remota!");
			aEx.printStackTrace();
		}
		catch (RemoteException rEx) {
			System.err.println("No se encontró el servicio o hubo errores al llamar a los métodos remotos!");
			rEx.printStackTrace();
		}
		catch (ExplicaException eEx) {
			System.err.println("Error accediendo a la BD para obtener el listado de productos!");
			eEx.printStackTrace();
		}
		
		return this.lRegistries;
	}
	
	@Override
	public void fillEntityData() {
		if (this.getSelectedEntity() != null && this.entEditView != null) {
			ProductOT selProduct = (ProductOT)this.getSelectedEntity();
			// Set up the product's reference
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_REFERENCE_WIDGETNAME)).setText(selProduct.getReference());
			// Set up the product's description
			((StyledText)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_DESCRIPTION_WIDGETNAME)).setText(selProduct.getDescription());
			// Set up the product's family
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_FAMILY_WIDGETNAME)).setText(selProduct.getGroup().getDescription());
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_FAMILY_WIDGETNAME)).setData(selProduct.getGroup());

			// Set up the product's barcode
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_WIDGETNAME)).setText(selProduct.getBarcode());
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_TYPE_WIDGETNAME)).setText(selProduct.getBarcodeType().getDescription());
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_TYPE_WIDGETNAME)).setData(selProduct.getBarcodeType());
			Label labelBarcode = (Label)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_IMAGE_WIDGETNAME);
			Image imgBarcode = ImageUtils.getInstance().scale(
					BarcodeGenerator.createBarcodeImage(selProduct.getBarcode(), ExplicaGUIBuilder.getInstance().getDisplay()), 
					labelBarcode.getSize().x, labelBarcode.getSize().y);
			labelBarcode.setImage(imgBarcode);
			this.logger.debug(String.format("Image BARCODE: (%d, %d px) --> (%d, %d px)", 
					imgBarcode.getImageData().width, imgBarcode.getImageData().height,
					labelBarcode.getSize().x, labelBarcode.getSize().y));
//			labelBarcode.setSize(labelBarcode.computeSize(imgBarcode.getImageData().width+10, imgBarcode.getImageData().height+10));

			// Set up the product's VAT type
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_VAT_WIDGETNAME)).setText(selProduct.getVatType().getDescription());
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_VAT_WIDGETNAME)).setData(selProduct.getVatType());
			
			// Fill the product image widget with the first image from the list.
			this.currentImageIndex = 0;
			this.showSelectedProductImage();
			
			// Build the traceability tree for the product
			if (selProduct.getTrData() != null && selProduct.getTrData().length > 0) {
				TraceabilityTreeView.getInstance().openTraceabilityFile(selProduct.getTrData());
			}
			else {
				TraceabilityTreeView.getInstance().deleteTreeContents();
			}
	
			// Fill the extension catalog for the entity
			if (this.extFieldsView!=null)
				this.extFieldsView.clear();
			if (selProduct.getGroup() != null && selProduct.getGroup().getExtTable() != null) {
				this.extFieldsView.setExtTable(selProduct.getGroup().getExtTable());
				this.fillEntityExtensionTable(this.getSelectedId());
			}
/*			if (this.selProduct.getGroup() != null && this.selProduct.getGroup().getExtTable() != null) {
				this.fillEntityExtensionTable(this.selProduct.getGroup().getExtTable().getCodExtTable());
			}
*/
		
			// Fill the multi selection subentities for the entity
//			this.showSubentityMultiSelection();
/*			ExplicaDetailEntityView view = (ExplicaDetailEntityView) this.entEditView.getMultiSelectEntityView(InterfaceWarehouse.EXPLICA_ENTITY_MEASUREUNIT_ID);
			view.showEntityView();
			
			ExplicaDetailEntityView view2 = (ExplicaDetailEntityView) this.entEditView.getMultiSelectEntityView(InterfaceExplica.EXPLICA_ENTITY_PRICELISTLINE_ID);
			view2.showEntityView();
*/
			
			// Repaint the product edition dialog
			this.entityDialog.getShell().layout(true);
		}
	}
	
	@Override
	public void clearEntityData() {
		if (this.entEditView != null) {
			// Clear the product's reference
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_REFERENCE_WIDGETNAME)).setText("");
			// Clear the product's description
			((StyledText)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_DESCRIPTION_WIDGETNAME)).setText("");
			// Clear the product's family
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_FAMILY_WIDGETNAME)).setText("");
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_FAMILY_WIDGETNAME)).setData(null);
			// Clear the product's barcode
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_WIDGETNAME)).setText("");
			// Clear the product's barcode type
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_TYPE_WIDGETNAME)).setText("");
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_TYPE_WIDGETNAME)).setData(null);
			// Clear the product's barcode image
			Label labelBarcode = (Label)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_IMAGE_WIDGETNAME);
			labelBarcode.setImage(null);
			// Clear the product's image
			Label labelImg = (Label)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_IMAGE_WIDGETNAME);
			labelImg.setImage(null);
			// Clear the product's vat type
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_VAT_WIDGETNAME)).setText("");
			((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_VAT_WIDGETNAME)).setData(null);
			// Clear the product's traceability tree viewer contents
			TraceabilityTreeView.getInstance().deleteTreeContents();
		}
	}

	@Override
	public void selectEntity(Long idEntity) {
		super.selectEntity(idEntity);
		ProductOT selProduct = (ProductOT)this.selectedEntity;
		if (this.selectedEntity != null && selProduct.getImages() != null && selProduct.getImages().size() > 0) {
			this.selProductImages = new ArrayList(selProduct.getImages());
		}
		else {
			this.selProductImages = new ArrayList();
		}
	}
	
	private void connectEvents() {
		// Connect the product's barcode text to its handler to update the product's barcode image
		Text productBarcode = (Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_WIDGETNAME);
		ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_CHANGED,
				productBarcode,
				InterfaceWarehouse.EDIT_PRODUCT_BARCODE_CHANGED_HANDLER,
				this.productListener);
		
		// Connect the product's dialog to its handler to resize the product contents properly
		SwtDialog productDialog = this.getDialog(InterfaceWarehouse.EDIT_PRODUCT_DIALOG_NAME);
		ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_SIZEREQUEST,
				productDialog.getShell(),
				InterfaceWarehouse.EDIT_PRODUCT_RESIZED_HANDLER,
				this.productListener);
	}
	
	private void connectProductPhotoButtons() {
		ClientContext.getInstance().getLogger().debug("CONNECTING ... " + this);
		// Get the product photo First button
		Button buttonFirst = (Button)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_FIRST_IMAGE_BUTTON_WIDGETNAME);
		// Connect the signal to the button
		ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLICKED, buttonFirst, 
				InterfaceWarehouse.EDIT_PRODUCT_IMAGE_FIRST_BUTTON_CLICKED_HANDLER, this.productListener);
		// Get the product photo Last button
		Button buttonLast = (Button)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_LAST_IMAGE_BUTTON_WIDGETNAME);
		// Connect the signal to the button
		ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLICKED, buttonLast, 
				InterfaceWarehouse.EDIT_PRODUCT_IMAGE_LAST_BUTTON_CLICKED_HANDLER, this.productListener);
		// Get the product photo Next button
		Button buttonNext = (Button)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_NEXT_IMAGE_BUTTON_WIDGETNAME);
		// Connect the signal to the button
		ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLICKED, buttonNext, 
				InterfaceWarehouse.EDIT_PRODUCT_IMAGE_NEXT_BUTTON_CLICKED_HANDLER, this.productListener);
		// Get the product photo Previous button
		Button buttonPrevious = (Button)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_PREVIOUS_IMAGE_BUTTON_WIDGETNAME);
		// Connect the signal to the button
		ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLICKED, buttonPrevious, 
				InterfaceWarehouse.EDIT_PRODUCT_IMAGE_PREVIOUS_BUTTON_CLICKED_HANDLER, this.productListener);
		
		// Get the product photo Add button
		Button buttonAdd = (Button)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_ADD_IMAGE_BUTTON_WIDGETNAME);
		// Connect the signal to the button
		ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLICKED, buttonAdd, 
				InterfaceWarehouse.EDIT_PRODUCT_IMAGE_ADD_BUTTON_CLICKED_HANDLER, this.productListener);
		
		// Get the product photo Delete button
		Button buttonDel = (Button)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_DELETE_IMAGE_BUTTON_WIDGETNAME);
		// Connect the signal to the button
		ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLICKED, buttonDel, 
				InterfaceWarehouse.EDIT_PRODUCT_IMAGE_DELETE_BUTTON_CLICKED_HANDLER, this.productListener);
	}
	
	private boolean hasNextProductImage() {
		boolean hasNext = this.selProductImages != null && this.currentImageIndex < this.selProductImages.size() - 1;
		
		this.logger.debug("Product image hasNext=" + hasNext);
		return hasNext;
	}
	
	private boolean hasPreviousProductImage() {
		boolean hasPrev = this.selProductImages != null && this.currentImageIndex > 0;
		
		this.logger.debug("Product image hasPrevious=" + hasPrev);
		return hasPrev;
	}
	
	private void nextProductImage() {
		if (this.hasNextProductImage()) {
			this.currentImageIndex++;
		}
	}
	
	private void prevProductImage() {
		if (this.hasPreviousProductImage()) {
			this.currentImageIndex--;
		}
	}
	
	public void showFirstProductImage() {
		this.currentImageIndex = 0;
		this.showSelectedProductImage();
	}
	public void showLastProductImage() {
		this.currentImageIndex = this.selProductImages.size()-1;
		this.showSelectedProductImage();
	}
	public void showPreviousProductImage() {
		this.prevProductImage();
		this.showSelectedProductImage();
	}
	public void showNextProductImage() {
		this.nextProductImage();
		this.showSelectedProductImage();
	}
	public void addProductImage() {
		// Open a new file dialog to select the image file
		FileDialog d = new FileDialog(this.entityDialog.getShell(), SWT.NONE);
		String[] ext = new String[] {"*.jpg", "*.png", "*.gif", "*.*"};
		d.setFilterExtensions(ext);
		String filename = d.open();
		
		if (filename != null && filename.length() > 0) {
			// Add image to the product images' list
			ImageOT img = new ImageOT();
			img.setPath(d.getFileName());
			img.setContents(ImageUtils.getInstance().getImageContents(filename));
			
			if (this.selProductImages == null)
				this.selProductImages = new ArrayList<ImageOT>();
			
			this.selProductImages.add(img);
			this.logger.info(String.format("Product image added (%s)! The product has (%d) images.", 
					img.getPath(), this.selProductImages.size()));
			

			// Show the new product image
			this.currentImageIndex = this.selProductImages.size() - 1;
			this.showSelectedProductImage();
//			this.selProduct.getImages().add(img);
			System.out.println("Fin de añadir: " + this.currentImageIndex + ", " + this.selProductImages.size());
			
			try {
				this.logger.debug("Añadiendo nueva imagen: " + d.getFileName());
				this.getRemote().saveImage(d.getFileName(), img.getContents());
			}
			catch (Exception ex) {
				ex.printStackTrace();
			}
		} // if user selected a valid image
	}
	
	
	public void delProductImage() {
		// Remove the selected product image
		if (this.selProductImages != null && this.currentImageIndex >= 0 && this.currentImageIndex < this.selProductImages.size()) {
			ImageOT delImg = this.selProductImages.get(this.currentImageIndex);
			this.selProductImages.remove(this.currentImageIndex);
			
			this.logger.info(String.format("Product image deleted (%s)! The product has (%d) images.", 
					delImg.getPath(), this.selProductImages.size()));
			
			// If there are any other image, show the previous one
			if (this.selProductImages.size() > 0) {
				this.currentImageIndex--;
			}
			// If there are no more images, clear the product image shown
			else {
				this.currentImageIndex = 0;
			}
			
			this.showSelectedProductImage();
		}
	}
	
	
	public void showSelectedProductImage() {
		// Set up the product's image
		if (this.selProductImages != null && this.currentImageIndex >= 0 && this.currentImageIndex < this.selProductImages.size()) {
			ImageOT selImage = this.selProductImages.get(this.currentImageIndex);
			Label labelImg = (Label)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_IMAGE_WIDGETNAME);
			System.out.println(selImage.getContents());
			Image img = ImageUtils.getInstance().getScaledImage(selImage.getContents(), labelImg.getSize().x, labelImg.getSize().y);
			
			labelImg.setImage(img);
			this.logger.debug(String.format("Image %s: (%d, %d px) --> (%d, %d px)", selImage.getPath(), 
					img.getImageData().width, img.getImageData().height,
					labelImg.getSize().x, labelImg.getSize().y));
		} // if there is any selected product image
		// If null product image --> clear the image
		else {
			Label labelImg = (Label)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_IMAGE_WIDGETNAME);
			labelImg.setImage(null);
		}
		
		this.enableProductImageButtons();
	}
	
	private void enableProductImageButtons() {
		// Get the product photo First button
		Button buttonFirst = (Button)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_FIRST_IMAGE_BUTTON_WIDGETNAME);
		// Get the product photo Previous button
		Button buttonPrevious = (Button)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_PREVIOUS_IMAGE_BUTTON_WIDGETNAME);
		// Get the product photo Last button
		Button buttonLast = (Button)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_LAST_IMAGE_BUTTON_WIDGETNAME);
		// Get the product photo Next button
		Button buttonNext = (Button)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_NEXT_IMAGE_BUTTON_WIDGETNAME);
		
		// If has later images to show
		if (this.hasNextProductImage()) {
			buttonNext.setEnabled(true);
			buttonLast.setEnabled(true);
		}
		else {
			buttonNext.setEnabled(false);
			buttonLast.setEnabled(false);
		}
		// If has previous images to show
		if (this.hasPreviousProductImage()) {
			buttonPrevious.setEnabled(true);
			buttonFirst.setEnabled(true);
		}
		else {
			buttonPrevious.setEnabled(false);
			buttonFirst.setEnabled(false);
		}
	}

	@Override
	public OperationResult saveEntity() {
		OperationResult result = new OperationResult();

		OperationResult resultValidation = validateEntity();
		if (resultValidation != null)
			if (resultValidation.getResult() != OperationResult.RESULT_OK) {
				return resultValidation;
			}

		ProductOT entity = (ProductOT)this.getEntityData();
		
		this.logger.debug("Saving entity:" + entity.toString());

		if (entity == null) {
			result.addResultMessage(OperationResult.RESULT_ERROR, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							InterfaceErrors.ERR_SAVE_ENTITY_NULL));
			ExplicaGUIBuilder.getInstance().showConfirmationDialog(
					this.entEditView.getGui().getParentWindow().getShell(),
					"Error grabando null entity", "ERROR", SWT.ICON_ERROR,
					SWT.OK);
			return result;
		}

		result.add(saveEntity(entity));

		if (result.getResult() == OperationResult.RESULT_OK) {
			if (extFieldsView != null)
				result.add(this
						.saveEntityExtensionTable(entity.getInternalId()));
		}
		else {
			result.getResultMessagesList().get(0).getExc().printStackTrace();
		}
		
		if (result.getResult() == OperationResult.RESULT_OK) {

			BaseVO newEntity = this.refreshEntity(entity);
			if (newEntity == null)
				fireExceptionAndExit("Error. Cant not refresh entity");
			this.updateRegistry(newEntity);
			this.updateViews(false);
		}
		
		return result;
	}

	@Override
	public OperationResult saveEntity(BaseVO entity) {
		OperationResult result = new OperationResult();
	
		// Call the remote object to save the contents of the product
		try {
			WarehouseManager manager = this.getRemoteWarehouse();
			
			ProductOT product = (ProductOT)entity;
			result = manager.saveProduct(product);
		}
		catch (ExplicaException ex) {
			System.err.println("Error guardando producto!");
			ex.printStackTrace();
			result.addResultMessage(OperationResult.RESULT_ERROR, ex.getResMsg());
		}
		catch (RemoteException rEx) {
			System.err.println("No se encontró el servicio o hubo errores al llamar a los métodos remotos!");
			rEx.printStackTrace();
			
			result.addResultMessage(OperationResult.RESULT_ERROR, 
					ClientContext.getInstance().getMsgCatalog().newResultMessage(InterfaceWarehouseErrors.ERR_RMI_METHOD_NOT_FOUND, rEx));
		}
		
		return result;
	}
	
	private WarehouseManager getRemoteWarehouse() throws ExplicaException {
		try {
			// El servidor de registro de RMI devuelve un objeto remoto genérico
			// que debe ser convertido al tipo correspondiente. Ojo: El nombre por el
			// que buscamos debe coincidir con el que se le dio al servicio en el
			// momento en que se registró (WarehouseManagerImpl.java)
			Registry registry = LocateRegistry.getRegistry(InterfaceExplica.RMI_REGISTRY_PORT);
            System.out.println("Registry located");
			WarehouseManager manager = (WarehouseManager)registry.lookup(InterfaceExplica.JNDI_WAREHOUSE_MANAGER_EXPORT_NAME);
			System.out.println("WarehouseManager located");
			
			return manager;
		}
		catch (AccessException aEx) {
			System.err.println("Se rechazó el acceso. Su sistema no tiene los permisos necesarios para realizar la operación remota!");
			aEx.printStackTrace();
			
			throw new ExplicaException(ClientContext.getInstance().getMsgCatalog().newResultMessage(
					InterfaceWarehouseErrors.ERR_RMI_NO_ACCESS, aEx, (Object)InterfaceExplica.JNDI_WAREHOUSE_MANAGER_EXPORT_NAME, (Object)null));
		}
		catch (NotBoundException nEx) {
			System.err.println("El nombre del objeto no está asociado a un objeto remoto registrado!");
			nEx.printStackTrace();
			
			throw new ExplicaException(ClientContext.getInstance().getMsgCatalog().newResultMessage(
					InterfaceWarehouseErrors.ERR_RMI_NOT_BOUND, nEx, (Object)InterfaceExplica.JNDI_WAREHOUSE_MANAGER_EXPORT_NAME, (Object)null));
		}
		catch (RemoteException rEx) {
			System.err.println("No se encontró el servicio o hubo errores al llamar a los métodos remotos!");
			rEx.printStackTrace();
			
			throw new ExplicaException(ClientContext.getInstance().getMsgCatalog().newResultMessage(
					InterfaceWarehouseErrors.ERR_RMI_METHOD_NOT_FOUND, rEx, (Object)InterfaceExplica.JNDI_WAREHOUSE_MANAGER_EXPORT_NAME, (Object)null));
		}
	}

	@Override
	public void updateEntityData() {
		if (this.getSelectedEntity() != null && this.entEditView != null) {
			ProductOT selProduct = (ProductOT)this.getSelectedEntity();
			// Set up the product's reference
			selProduct.setReference(((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_REFERENCE_WIDGETNAME)).getText());
			// Set up the product's description
			selProduct.setDescription(((StyledText)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_DESCRIPTION_WIDGETNAME)).getText());
			// Set up the product's family
			selProduct.setGroup((ProductGroupOT)((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_FAMILY_WIDGETNAME)).getData());
			// Set up the product's barcode
			selProduct.setBarcode(((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_WIDGETNAME)).getText());
			// Set up the product's barcode type
			selProduct.setBarcodeType((BarcodeTypeOT)((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_TYPE_WIDGETNAME)).getData());
			// Set up the product's VAT type
			selProduct.setVatType((VatTypeOT)((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_VAT_WIDGETNAME)).getData());
			// Set up the images of the selected product
			if (this.selProductImages != null)
				selProduct.setImages(new HashSet(this.selProductImages));			
		}
	}

	@Override
	public BaseVO getEntityData() {
		ProductOT product = new ProductOT();
		
		if (this.entEditView != null) {
			// Set up the product's reference
			product.setReference(((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_REFERENCE_WIDGETNAME)).getText());
			// Set up the product's description
			product.setDescription(((StyledText)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_DESCRIPTION_WIDGETNAME)).getText());
			// Set up the product's family
			product.setGroup((ProductGroupOT)((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_FAMILY_WIDGETNAME)).getData());
			// Set up the product's barcode
			product.setBarcode(((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_WIDGETNAME)).getText());
			// Set up the product's barcode type
			product.setBarcodeType((BarcodeTypeOT)((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_TYPE_WIDGETNAME)).getData());
			// Set up the product's VAT type
			product.setVatType((VatTypeOT)((Text)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_VAT_WIDGETNAME)).getData());
			// Set up the images of the selected product
			if (this.selProductImages != null)
				product.setImages(new HashSet(this.selProductImages));
			// Set up the product's traceability tree contents
			try {
				ByteArrayOutputStream trOs = new ByteArrayOutputStream();
				TraceabilityTreeView.getInstance().saveTraceabilityTree(trOs);
				product.setTrData(trOs.toByteArray());
			}
			catch (Exception ex) {
				ex.printStackTrace();
				product.setTrData(null);
			}
			// Set up the product's measure units set
			ExplicaDetailEntityView view = this.entEditView.getMultiSelectEntityView(InterfaceWarehouse.EXPLICA_ENTITY_MEASUREUNIT_ID);
			product.setMeasureUnits(new HashSet(view.getRegistries()));
			
			// Set up the product's price list line set
			ExplicaDetailEntityView view2 = this.entEditView.getMultiSelectEntityView(InterfaceExplica.EXPLICA_ENTITY_PRICELISTLINE_ID);
			product.setPrices(new HashSet(view2.getRegistries()));
/*			for (Object line : product.getPrices()) {
				PriceListLineOT pll = (PriceListLineOT)line;
				pll.getPriceList().getLines().add(pll);
			}
*/
		}
		
		if (this.getSelectedEntity() != null) {
			ProductOT selProduct = (ProductOT)this.getSelectedEntity();
			product.setVersion(selProduct.getVersion());
			product.setIdProduct(selProduct.getIdProduct());
		}
		
		return product;
	}

	@Override
	public void setEditionMode(boolean enabled) {
		// Get the product's reference widget
		Control c = (Control)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_REFERENCE_WIDGETNAME);
		c.setEnabled(enabled);
		// Get the product's description widget
		c = (Control)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_DESCRIPTION_WIDGETNAME);
		c.setEnabled(enabled);
		// Get the product's family widget
		c = (Control)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_FAMILY_WIDGETNAME);
		c.setEnabled(enabled);
		// Get the product's barcode widget
		c = (Control)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_WIDGETNAME);
		c.setEnabled(enabled);
		// Get the product's barcode type widget
		c = (Control)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_TYPE_WIDGETNAME);
		c.setEnabled(enabled);
		// Get the product's VAT widget
		c = (Control)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_VAT_WIDGETNAME);
		c.setEnabled(enabled);
		// Get the product's add image widget
		c = (Control)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_ADD_IMAGE_BUTTON_WIDGETNAME);
		c.setEnabled(enabled);
		// Get the product's delete image widget
		c = (Control)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_DELETE_IMAGE_BUTTON_WIDGETNAME);
		c.setEnabled(enabled);
		// Get the product's select product group widget
		c = (Control)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_SELECT_PRODUCT_GROUP_BUTTON_WIDGETNAME);
		c.setEnabled(enabled);
		// Get the product's select barcode type widget
		c = (Control)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_SELECT_BARCODE_TYPE_BUTTON_WIDGETNAME);
		c.setEnabled(enabled);
		// Get the product's select VAT type widget
		c = (Control)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_SELECT_VAT_TYPE_BUTTON_WIDGETNAME);
		c.setEnabled(enabled);
		// Get the product's save button widget
		c = (Control)this.getWidget(InterfaceExplica.EXPLICA_ENTITYEDITION_SAVE_BUTTON_NAME);
		c.setEnabled(enabled);
		// Get the product's undo button widget
		c = (Control)this.getWidget(InterfaceExplica.EXPLICA_ENTITYEDITION_UNDO_BUTTON_NAME);
		c.setEnabled(enabled);
		// Get the product's measure unit tab item widget
		c = (Control)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_MEASUREUNIT_PANEL_WIDGETNAME);
		c.setEnabled(enabled);
		// Get the product's extension catalog tab item widget
		c = (Control)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_CATALOG_TAB_WIDGETNAME);
		c.setEnabled(enabled);
	}

	@Override
	public void build_extension_fields_view() {
		this.extFieldsView = new ExplicaExtensionFieldsView(this.entEditView.getGui());
		this.extFieldsView.setExtCatalog((Tree) this.getWidget(
				InterfaceExplica.EXPLICA_ENTITY_EXTENSION_CATALOG_NAME));
		this.extFieldsView.setLogger(this.logger);
		this.extFieldsView.setEntityLauncher(this);
	}

	@Override
	public void buildSelectionSets() {
		// Initialize the set of subentity selection widgets
		lSelectionSubentities = new HashSet<SelectionSubentityOT>();
		
		// Add product group selection button
		lSelectionSubentities.add(new SelectionSubentityOT(
				InterfaceWarehouse.EXPLICA_ENTITY_PRODUCTGROUP_ID,
				InterfaceWarehouse.EDIT_PRODUCT_FAMILY_WIDGETNAME,
				this, (Button)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_SELECT_PRODUCT_GROUP_BUTTON_WIDGETNAME)));
	
		// Add the barcode type selection button
		lSelectionSubentities.add(new SelectionSubentityOT(
				InterfaceExplica.EXPLICA_ENTITY_BARCODETYPE_ID,
				InterfaceWarehouse.EDIT_PRODUCT_BARCODE_TYPE_WIDGETNAME,
				this, (Button)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_SELECT_BARCODE_TYPE_BUTTON_WIDGETNAME)));
		// Add the VAT type selection button
		lSelectionSubentities.add(new SelectionSubentityOT(
				InterfaceExplica.EXPLICA_ENTITY_VATTYPE_ID,
				InterfaceWarehouse.EDIT_PRODUCT_VAT_WIDGETNAME,
				this, (Button)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_SELECT_VAT_TYPE_BUTTON_WIDGETNAME)));
		
		// Initialize the set of subentity multiselection widgets
		lMultiSelectionSubentities = new HashSet<MultiSelectionSubentityOT>();
		
		// Add the measure unit multiselection subentity
		lMultiSelectionSubentities.add(new MultiSelectionSubentityOT(
				InterfaceWarehouse.EXPLICA_ENTITY_MEASUREUNIT_ID,
				InterfaceWarehouse.EDIT_PRODUCT_MEASUREUNIT_TABLE_WIDGETNAME, this, this.getSwtWidget(
						InterfaceWarehouse.EDIT_PRODUCT_MEASUREUNIT_PANEL_WIDGETNAME), "measureUnits", null));
		
		// Add the price list line multiselection subentity
		lMultiSelectionSubentities.add(new MultiSelectionSubentityOT(
				InterfaceExplica.EXPLICA_ENTITY_PRICELISTLINE_ID,
				InterfaceWarehouse.EDIT_PRODUCT_PRICELIST_TABLE_WIDGETNAME, this, this.getSwtWidget(
						InterfaceWarehouse.EDIT_PRODUCT_PRICELIST_PANEL_WIDGETNAME), "prices", "product"));
		
		// Add the price list line multiselection subentity
		lMultiSelectionSubentities.add(new MultiSelectionSubentityOT(
				InterfaceWarehouse.EXPLICA_ENTITY_PRODUCTSTOCK_ID,
				InterfaceWarehouse.EDIT_PRODUCT_STOCK_TABLE_WIDGETNAME, this, this.getSwtWidget(
						InterfaceWarehouse.EDIT_PRODUCT_STOCK_PANEL_WIDGETNAME), "stocks", "product"));
	}

	@Override
	public void getWidgets() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void init_specific_components() {
		this.logger.info(String.format("Building entity dialog: %s", this.entityData.getName()));
		
		Label labelBarcode = (Label)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_BARCODE_IMAGE_WIDGETNAME);
		System.out.println("labelBarcode = " + labelBarcode);
		this.logger.debug(String.format("BARCODE SIZE: (%d, %d px) --> BOUNDS: (%d, %d px)", 
				labelBarcode.getSize().x, labelBarcode.getSize().y,
				labelBarcode.getBounds().width, labelBarcode.getBounds().height));
		
		// Connect the product photo buttons events to their handlers
		this.connectProductPhotoButtons();

		// Build the traceability tree viewer tab
		this.addTrazabilityTree((TabFolder)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_NOTEBOOK_WIDGETNAME));
		
/*
		// Build the traceability tree viewer tab
		try {
			// Get the tab folder widget
			TabFolder productTab = (TabFolder)this.getWidget(InterfaceWarehouse.EDIT_PRODUCT_NOTEBOOK_WIDGETNAME);
			
			// Create a new tab for embedding the traceability tree viewer
			TabItem trViewerTab = (TabItem)ExplicaGUIBuilder.getInstance().getToolkit().
					tabItem(productTab, "productTrViewerTab");
			ExplicaGUIBuilder.getInstance().getToolkit().setTabItemLabel(trViewerTab, ClientContext.getInstance().getI18n().tr("Traceability"));
			this.entEditView.getGui().addWidget(InterfaceExplica.EXPLICA_ENTITY_PANEL_NAME + "_" + this.entityData.getName(),
					trViewerTab,
					InterfaceWarehouse.EDIT_PRODUCT_NOTEBOOK_WIDGETNAME);
			
			Composite trViewerPanel = (Composite)ExplicaGUIBuilder.getInstance().getToolkit().
					emptyPanel(trViewerTab.getParent(), "productTrViewerPanel");
			ExplicaGUIBuilder.getInstance().getToolkit().addTabItemContent(trViewerTab, trViewerPanel);
			trViewerPanel.setLayout(new FillLayout());
			this.entEditView.getGui().addWidget(InterfaceExplica.EXPLICA_ENTITY_PANEL_NAME + "_" + this.entityData.getName(),
					trViewerPanel,
					"productTrViewerTab");
			
			TraceabilityTreeView treeView = TraceabilityTreeView.getInstance();
			
			this.logger.info("Building traceability tree viewer: " + this.getClass().getResource(InterfaceTraceabilityTree.TREEVIEWER_GLADE_FILE).getPath());
			treeView.buildTreeView(InterfaceTraceabilityTree.TREEVIEWER_GLADE_FILE, 
					this.entEditView.getGui().getSwtWidget("productTrViewerPanel"), ExplicaGUIBuilder.getInstance().getGUI(InterfaceExplica.EXPLICA_CORE_GLADE_NAME));
		}
		catch (Exception ex) {
			ex.printStackTrace();
		}
*/
		
		// Save the entity dialog instance for latter use.
/*		SwtDialog d = this.entEditView.getDialog();
		d.getShell().setMinimumSize(800, 600);
		d.getShell().setSize(800, 600);
		d.getShell().setBackground(ExplicaGUIBuilder.getInstance().getColor(SWT.COLOR_BLUE));
		
		this.setEntityDialog(d);
*/
		// Set up the JavaGlade in the product listener
		this.productListener.setGui(this.entEditView.getGui());
		
		// Connect the specific product events
		this.connectEvents();
		
	}

	@Override
	public void setWidgetsValues(BaseVO entity) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public OperationResult validateEntity() {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	protected BaseVO loadEntity(Long idEntity) throws ExplicaException {
		this.logger.debug("Loading entity: " + idEntity);
		BaseVO result = null;
		try {
			WarehouseManager manager = this.getRemoteWarehouse();
			if (idEntity != null && idEntity != 0) {
				result = manager.getProduct(idEntity);
			} else {
				result = null;
			}
		} catch (ExplicaException e) {
			e.printStackTrace();
			throw e;
		} catch (RemoteException e) {
			e.printStackTrace();
			throw new ExplicaException(new ResultMessage(InterfaceErrors.ERR_RMI_NO_ACCESS, e));
		}

		return result;
	}
	
	@Override
	protected List<BaseVO> loadEntities() throws ExplicaException {
		this.logger.debug("Loading entities: " + this.getClassEntity().getCanonicalName());
		List <BaseVO> result = null;
		try {
			WarehouseManager manager = getRemoteWarehouse();
			result = manager.queryProducts(null, null);
		} catch (ExplicaException e) {
			e.printStackTrace();
			throw e;
		} catch (RemoteException e) {
			e.printStackTrace();
			throw new ExplicaException(new ResultMessage(InterfaceErrors.ERR_RMI_NO_ACCESS, e));
		}

		return result;
	}
	
	/**
	 * Returns tag Id assigned to CVS source file.
	 */
	public static String getRevision() {
		return "$Id: ProductClient.java,v 1.22 2009-10-27 10:09:31 mario Exp $";
	}
}
